/*!
    \file    dmx512_receiver.c
    \brief   DMX512接收器驱动实现文件（基于GD32C231C单片机）

    \version 2025-01-20, V1.0.0, DMX512接收器驱动 for GD32C231C
*/

// 包含头文件：驱动核心头文件、系统滴答定时器头文件、字符串/标准输入输出库
#include "dmx512_receiver.h"  // DMX512接收器驱动头文件（定义句柄、枚举、宏等）
#include "systick.h"          // 系统滴答定时器头文件（用于时间戳获取）
#include <string.h>           // 字符串操作库（memset、memcpy等函数）
#include <stdio.h>            // 标准输入输出库（printf调试输出）

/* 全局DMX512接收器句柄 */
// 存储接收器的所有状态、配置、数据缓冲区和统计信息，全局可见便于中断服务函数访问
dmx512_rx_handle_t g_dmx512_rx;

/* 静态函数声明 */
// 静态函数仅在本文件内可见，用于驱动内部初始化、状态处理等私有逻辑
static void dmx512_rx_gpio_config(void);    // GPIO引脚配置（UART_RX引脚初始化）
static void dmx512_rx_dma_config(void);     // DMA配置（外设到内存传输，用于批量数据接收）
static void dmx512_rx_timer_config(void);   // 定时器配置（预留超时检测，当前因资源限制禁用）
static void dmx512_rx_reset_state(void);    // 重置接收器状态（清空缓冲区、复位标志位）
static void dmx512_rx_process_break(void);  // 处理Break信号（DMX512帧起始标志）
static void dmx512_rx_process_data(uint8_t data);  // 处理单字节数据（Break后首字节或异常数据）
static void dmx512_rx_complete_frame(void); // 完成帧接收（数据校验、缓冲区复制、回调触发）
static void dmx512_rx_handle_error(dmx512_rx_error_t error);  // 错误处理（记录错误、触发回调）
static uint32_t dmx512_rx_get_time_us(void); // 获取微秒级时间戳（基于SysTick）

/*!
    \brief      初始化DMX512接收器
    \param[in]  none
    \param[out] none
    \retval     none
    \note       初始化流程：句柄清零→GPIO配置→UART配置→DMA配置→调试信息输出
                因GD32C231C定时器资源有限，暂禁用超时检测功能
*/
void dmx512_rx_init(void)
{
    /* 1. 初始化接收器句柄：清空所有成员变量，避免脏数据 */
    memset(&g_dmx512_rx, 0, sizeof(dmx512_rx_handle_t));
    g_dmx512_rx.state = DMX512_RX_STATE_IDLE;    // 初始状态：空闲
    g_dmx512_rx.error = DMX512_RX_ERROR_NONE;    // 初始错误：无错误
    g_dmx512_rx.frame_ready = false;             // 初始帧状态：无就绪帧
    g_dmx512_rx.receiving = false;               // 初始接收状态：未启动接收
    
    /* 初始化调试信息结构体 */
    g_dmx512_rx.debug_info.event = DMX512_DEBUG_EVENT_NONE;
    g_dmx512_rx.debug_info.pending = false;
    g_dmx512_rx.debug_info.data_byte = 0;
    g_dmx512_rx.debug_info.dma_received = 0;
    g_dmx512_rx.debug_info.total_received = 0;
    g_dmx512_rx.debug_info.remaining = 0;
    
    /* 2. 配置GPIO：初始化UART_RX引脚（PA3） */
    dmx512_rx_gpio_config();
    /* 3. 配置DMA：初始化DMA通道，用于UART接收数据的批量传输（减轻CPU负担） */
    dmx512_rx_dma_config();
    /* 4. 调试信息输出：通过串口打印初始化完成信息，便于开发调试 */
    printf("\r\nDMX512接收器初始化完成 - USART1 RX (PA3), 250kbps, 8N2");
}

/*!
    \brief      反初始化DMX512接收器
    \param[in]  none
    \param[out] none
    \retval     none
    \note       反初始化流程：停止接收→禁用外设→清空句柄，用于设备断电或重新配置前
*/
void dmx512_rx_deinit(void)
{
    /* 1. 停止接收：调用停止函数，确保接收中断、DMA均已禁用 */
    dmx512_rx_stop();
    
    
    /* 2. 禁用UART外设：关闭UART时钟或禁用UART模块（视硬件需求调整） */
    usart_disable(DMX512_RX_UART);
    
    /* 3. 重置句柄：清空所有状态，避免后续误操作 */
    memset(&g_dmx512_rx, 0, sizeof(dmx512_rx_handle_t));
}

/*!
    \brief      启动DMX512接收
    \param[in]  none
    \param[out] none
    \retval     none
    \note       启动流程：重置状态→使能UART接收中断→启用UART接收→更新状态标志
                仅在未接收状态下执行，避免重复启动
*/
void dmx512_rx_start(void)
{
    // 仅当未处于接收状态时执行启动逻辑，防止重复配置导致异常
    if (!g_dmx512_rx.receiving) {
        /* 1. 重置状态：清空缓冲区、复位通道计数、清除错误标志 */
        dmx512_rx_reset_state();
        
        /* 2. 启用UART接收相关中断：
           - 禁用USART_INT_RBNE：完全避免高频中断，只依赖DMA接收
           - USART_INT_IDLE：空闲线路检测（用于检测DMX512的Break信号）
           - USART_INT_ERR：错误中断（奇偶校验错、帧错误等） */
        /* usart_interrupt_enable(DMX512_RX_UART, USART_INT_RBNE); */ /* 完全禁用RBNE中断 */
        usart_interrupt_enable(DMX512_RX_UART, USART_INT_IDLE);  /* 空闲线路检测中断 */
        usart_interrupt_enable(DMX512_RX_UART, USART_INT_ERR);   /* 错误中断 */
        
        /* 3. 启用UART接收功能：允许UART模块接收外部数据 */
        usart_receive_config(DMX512_RX_UART, USART_RECEIVE_ENABLE);
        
        /* 4. 更新接收状态标志：标记为正在接收，状态切换为空闲（等待Break信号） */
        g_dmx512_rx.receiving = true;
        g_dmx512_rx.state = DMX512_RX_STATE_IDLE;
        
        /* 5. 调试信息输出：打印启动状态，便于开发调试 */
        printf("\r\nDMX512接收器已启动");
    }
}

/*!
    \brief      停止DMX512接收
    \param[in]  none
    \param[out] none
    \retval     none
    \note       停止流程：禁用UART接收中断→禁用UART接收→禁用DMA→更新状态标志
                仅在接收状态下执行，避免重复停止
*/
void dmx512_rx_stop(void)
{
    // 仅当处于接收状态时执行停止逻辑，防止重复配置导致异常
    if (g_dmx512_rx.receiving) {
        /* 1. 禁用UART接收相关中断：防止中断嵌套或误触发 */
        usart_interrupt_disable(DMX512_RX_UART, USART_INT_RBNE);
        usart_interrupt_disable(DMX512_RX_UART, USART_INT_IDLE);
        usart_interrupt_disable(DMX512_RX_UART, USART_INT_ERR);
        
        /* 2. 禁用UART接收功能：停止UART模块接收外部数据 */
        usart_receive_config(DMX512_RX_UART, USART_RECEIVE_DISABLE);
        
        /* 3. 禁用DMA通道：停止DMA数据传输，避免数据溢出 */
        dma_channel_disable(DMX512_RX_DMA_CHANNEL);
        
        /* 4. 更新接收状态标志：标记为未接收，状态切换为空闲 */
        g_dmx512_rx.receiving = false;
        g_dmx512_rx.state = DMX512_RX_STATE_IDLE;
        
        /* 5. 调试信息输出：打印停止状态，便于开发调试 */
        printf("\r\nDMX512接收器已停止");
    }
}

/*!
    \brief      检查是否有新的DMX512帧准备就绪
    \param[in]  none
    \param[out] none
    \retval     true: 有新帧, false: 无新帧
    \note       应用层通过此函数判断是否需要读取新帧数据，避免空读或重复读取
*/
bool dmx512_rx_is_frame_ready(void)
{
    // 直接返回句柄中的帧就绪标志（原子操作，确保多线程/中断安全）
    return g_dmx512_rx.frame_ready;
}

/*!
    \brief      获取接收到的DMX512通道数据
    \param[in]  channel: 通道号 (1-512)
    \param[out] none
    \retval     通道值 (0-255), 如果通道无效返回0
    \note       DMX512标准通道数为1-512，通道1对应数据缓冲区索引1（索引0为起始码）
                仅在帧就绪时返回有效数据，否则返回0（避免读取未完成数据）
*/
uint8_t dmx512_rx_get_channel(uint16_t channel)
{
    // 校验通道号有效性（1-512）且帧已就绪，满足条件则返回对应通道数据，否则返回0
    if (channel >= 1 && channel <= g_dmx512_rx.channel_count && g_dmx512_rx.frame_ready) {
        return g_dmx512_rx.data_buffer[channel]; /* 通道1对应数组索引1（索引0为起始码） */
    }
    return 0; // 通道无效或帧未就绪，返回默认值0
}

/*!
    \brief      获取接收到的RGB数据
    \param[in]  start_channel: 起始通道号 (1-510)
    \param[out] none
    \retval     RGB颜色值（red/green/blue各0-255）
    \note       RGB数据通常占用3个连续通道（红→绿→蓝），故起始通道需满足1≤start_channel≤510
                仅在帧就绪时返回有效RGB值，否则返回全0（黑色）
*/
rgb_color_t dmx512_rx_get_rgb(uint16_t start_channel)
{
    rgb_color_t color = {0, 0, 0}; // 初始化RGB为黑色（默认值）
    
    // 校验起始通道有效性（1-510，确保后续2个通道不越界）且帧已就绪
    if (start_channel >= 1 && start_channel <= (g_dmx512_rx.channel_count - 2) && g_dmx512_rx.frame_ready) {
        color.red = g_dmx512_rx.data_buffer[start_channel];     /* 第1个通道：红色分量 */
        color.green = g_dmx512_rx.data_buffer[start_channel + 1]; /* 第2个通道：绿色分量 */
        color.blue = g_dmx512_rx.data_buffer[start_channel + 2];  /* 第3个通道：蓝色分量 */
    }
    
    return color;
}

/*!
    \brief      获取多个RGB数据
    \param[in]  start_channel: 起始通道号 (1-510)
    \param[out] colors: RGB颜色数组（用于存储输出的RGB数据）
    \param[in]  count: 要获取的RGB数量
    \param[out] none
    \retval     实际获取的RGB数量（可能小于请求数量，因通道数限制）
    \note       用于批量获取多个RGB设备的颜色数据（如LED灯带），每个RGB占用3个通道
                需确保colors指针非空，否则返回0（避免空指针访问）
*/
uint16_t dmx512_rx_get_rgb_array(uint16_t start_channel, rgb_color_t *colors, uint16_t count)
{
    uint16_t i, actual_count = 0; // actual_count：实际获取的RGB数量（初始为0）
    uint16_t channel = start_channel; // 当前操作的通道号（从起始通道开始）
    
    // 校验帧是否就绪、colors指针是否非空，不满足则返回0
    if (!g_dmx512_rx.frame_ready || colors == NULL) {
        return 0;
    }
    
    // 循环获取RGB数据：直到达到请求数量或通道越界
    for (i = 0; i < count && channel <= (g_dmx512_rx.channel_count - 2); i++) {
        colors[i].red = g_dmx512_rx.data_buffer[channel];     /* 红色分量 */
        colors[i].green = g_dmx512_rx.data_buffer[channel + 1]; /* 绿色分量 */
        colors[i].blue = g_dmx512_rx.data_buffer[channel + 2];  /* 蓝色分量 */
        channel += 3; // 下一个RGB的起始通道（当前RGB占用3个通道）
        actual_count++; // 实际获取数量+1
    }
    
    return actual_count; // 返回实际获取的RGB数量
}

/*!
    \brief      复制接收到的DMX512数据到指定缓冲区
    \param[out] buffer: 目标缓冲区（用于存储复制的数据）
    \param[in]  buffer_size: 目标缓冲区大小（字节数）
    \param[out] none
    \retval     实际复制的字节数（可能小于缓冲区大小或实际数据长度）
    \note       用于批量读取完整DMX512帧数据（包含起始码+所有通道），避免直接操作内部缓冲区
                采用memcpy实现，确保数据完整性，仅在帧就绪时执行复制
*/
uint16_t dmx512_rx_copy_data(uint8_t *buffer, uint16_t buffer_size)
{
    uint16_t copy_size = 0; // 实际复制的字节数（初始为0）
    
    // 校验帧是否就绪、目标缓冲区是否非空、缓冲区大小是否有效
    if (g_dmx512_rx.frame_ready && buffer != NULL && buffer_size > 0) {
        // 计算复制大小：取缓冲区大小和实际数据长度（起始码+通道数）的较小值
        copy_size = (buffer_size < (g_dmx512_rx.channel_count + 1)) ? buffer_size : (g_dmx512_rx.channel_count + 1);
        memcpy(buffer, g_dmx512_rx.data_buffer, copy_size); // 复制数据到目标缓冲区
    }
    
    return copy_size; // 返回实际复制的字节数
}

/*!
    \brief      标记当前帧已处理
    \param[in]  none
    \param[out] none
    \retval     none
    \note       应用层读取完帧数据后调用此函数，清除帧就绪标志，允许接收器接收下一帧
                避免应用层重复处理同一帧数据
*/
void dmx512_rx_frame_processed(void)
{
    // 清除帧就绪标志（原子操作，确保多线程/中断安全）
    g_dmx512_rx.frame_ready = false;
}

/*!
    \brief      获取接收统计信息
    \param[out] stats: 统计信息结构体指针（用于存储输出的统计数据）
    \param[out] none
    \retval     none
    \note       统计信息包括：接收帧数、有效帧数、错误帧数、最后一帧时间等
                需确保stats指针非空，否则无操作（避免空指针访问）
*/
void dmx512_rx_get_stats(dmx512_rx_stats_t *stats)
{
    // 校验stats指针是否非空，满足则复制统计信息到目标结构体
    if (stats != NULL) {
        memcpy(stats, &g_dmx512_rx.stats, sizeof(dmx512_rx_stats_t));
    }
}

/*!
    \brief      重置接收统计信息
    \param[in]  none
    \param[out] none
    \retval     none
    \note       用于清空历史统计数据（如累计帧数、错误数），重新开始统计
*/
void dmx512_rx_reset_stats(void)
{
    // 清空统计信息结构体（所有成员置0）
    memset(&g_dmx512_rx.stats, 0, sizeof(dmx512_rx_stats_t));
}

/*!
    \brief      获取当前接收状态
    \param[in]  none
    \param[out] none
    \retval     当前接收状态（枚举类型：空闲、Break检测、数据接收等）
    \note       应用层可通过此函数判断接收器当前工作状态，用于调试或异常处理
*/
dmx512_rx_state_t dmx512_rx_get_state(void)
{
    // 直接返回当前状态（原子操作，确保多线程/中断安全）
    return g_dmx512_rx.state;
}

/*!
    \brief      获取最后一次错误
    \param[in]  none
    \param[out] none
    \retval     错误类型（枚举类型：无错误、帧错误、DMA错误等）
    \note       应用层可通过此函数查询历史错误，用于问题定位
*/
dmx512_rx_error_t dmx512_rx_get_last_error(void)
{
    // 直接返回最后一次错误类型（原子操作，确保多线程/中断安全）
    return g_dmx512_rx.error;
}

/*!
    \brief      设置帧接收完成回调函数
    \param[in]  callback: 回调函数指针（参数：数据缓冲区、数据长度）
    \param[out] none
    \retval     none
    \note       当一帧DMX512数据接收完成后，会自动调用此回调函数
                应用层可通过回调函数实时处理新帧数据，无需轮询dmx512_rx_is_frame_ready()
*/
void dmx512_rx_set_frame_callback(void (*callback)(uint8_t *data, uint16_t length))
{
    // 存储回调函数指针到全局句柄，接收完成时触发
    g_dmx512_rx.frame_received_callback = callback;
}

/*!
    \brief      设置错误回调函数
    \param[in]  callback: 回调函数指针（参数：错误类型）
    \param[out] none
    \retval     none
    \note       当接收过程中发生错误（如起始码无效、DMA错误），会自动调用此回调函数
                应用层可通过回调函数实时处理错误（如打印日志、重启接收器）
*/
void dmx512_rx_set_error_callback(void (*callback)(dmx512_rx_error_t error))
{
    // 存储回调函数指针到全局句柄，发生错误时触发
    g_dmx512_rx.error_callback = callback;
}

/*!
    \brief      配置DMX512接收器GPIO
    \param[in]  none
    \param[out] none
    \retval     none
    \note       配置UART_RX引脚（PA3）为复用功能，上拉输入，低速输出
                复用功能号（DMX512_RX_AF）需根据GD32C231C datasheet确认（通常为AF1）
*/
static void dmx512_rx_gpio_config(void)
{
    /* 1. 使能GPIOA时钟：GD32外设时钟默认关闭，需手动使能 */
    rcu_periph_clock_enable(RCU_GPIOA);
    
    /* 2. 配置PA3为UART_RX复用功能：
       - gpio_af_set：设置引脚复用功能（AF1对应USART1）
       - gpio_mode_set：模式为复用功能，上拉输入（避免浮空噪声）
       - gpio_output_options_set：推挽输出（复用功能下无效，仅作配置），低速（降低功耗） */
    gpio_af_set(DMX512_RX_PORT, DMX512_RX_AF, DMX512_RX_PIN);
    gpio_mode_set(DMX512_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, DMX512_RX_PIN);
    gpio_output_options_set(DMX512_RX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_LEVEL_1, DMX512_RX_PIN);
}

/*!
    \brief      配置DMX512接收器DMA
    \param[in]  none
    \param[out] none
    \retval     none
    \note       配置DMA通道用于UART接收数据的批量传输（外设到内存）
                关键参数：传输方向、内存/外设地址、数据宽度、传输数量、优先级
                使能DMA传输完成中断，用于帧接收完成的判断
*/
static void dmx512_rx_dma_config(void)
{
    dma_parameter_struct dma_init_struct; // DMA初始化参数结构体
    
    /* 1. 使能DMA和DMAMUX时钟：GD32C231C使用DMAMUX（DMA多路复用器）分配请求源 */
    rcu_periph_clock_enable(RCU_DMA);
    rcu_periph_clock_enable(RCU_DMAMUX);
    
    /* 2. 复位DMA通道：清除之前的配置，避免脏数据影响 */
    dma_deinit(DMX512_RX_DMA_CHANNEL);
    
    /* 3. 配置DMA参数：初始化结构体成员 */
    dma_struct_para_init(&dma_init_struct); // 结构体成员默认初始化
    dma_init_struct.request = DMX512_RX_DMA_REQUEST; // DMA请求源（USART1_RX）
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY; // 传输方向：外设→内存
    dma_init_struct.memory_addr = (uint32_t)g_dmx512_rx.rx_buffer; // 内存地址：接收缓冲区
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; // 内存地址自增（批量传输）
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; // 内存数据宽度：8位（DMX512数据为字节）
    dma_init_struct.number = DMX512_RX_BUFFER_SIZE; // 传输数量：接收缓冲区大小（513字节）
    dma_init_struct.periph_addr = (uint32_t)&USART_RDATA(DMX512_RX_UART); // 外设地址：UART接收数据寄存器
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; // 外设地址不增（固定为UART_RDATA）
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; // 外设数据宽度：8位
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; // DMA优先级：极高（确保数据不丢失）
    dma_init(DMX512_RX_DMA_CHANNEL, &dma_init_struct); // 应用配置到DMA通道
    
    /* 4. 配置DMA模式：
       - 禁用循环模式（单次传输，每帧数据传输完成后需重新配置）
       - 禁用内存到内存模式（当前为外设到内存） */
    dma_circulation_disable(DMX512_RX_DMA_CHANNEL);
    dma_memory_to_memory_disable(DMX512_RX_DMA_CHANNEL);
    
    /* 5. 禁用DMAMUX同步模式：使用异步模式（默认），无需外部同步信号 */
    dmamux_synchronization_disable(DMAMUX_MUXCH0);
    
    /* 6. 启用USART接收FIFO以减少中断频率 */
    usart_receive_fifo_enable(DMX512_RX_UART);
    
    /* 7. 配置DMA中断：使能DMA传输完成中断，设置优先级为3（低优先级，避免抢占按键中断） */
    nvic_irq_enable(DMX512_RX_DMA_IRQ, 3);  /* 低优先级，避免抢占按键中断 */
    dma_interrupt_enable(DMX512_RX_DMA_CHANNEL, DMA_INT_FTF);  /* 传输完成中断（FTF：Full Transfer Flag） */
    
    /* 8. 使能UART的DMA接收功能：允许UART接收数据触发DMA传输 */
    usart_dma_receive_config(DMX512_RX_UART, USART_RECEIVE_DMA_ENABLE);
}

/*!
    \brief      重置接收状态
    \param[in]  none
    \param[out] none
    \retval     none
    \note       重置内容：状态、错误、通道计数、帧就绪标志、接收缓冲区
                用于接收器启动前、错误恢复后、帧接收完成后，确保状态干净
*/
static void dmx512_rx_reset_state(void)
{
    g_dmx512_rx.state = DMX512_RX_STATE_IDLE;          // 状态重置为空闲
    g_dmx512_rx.error = DMX512_RX_ERROR_NONE;          // 错误重置为无错误
    g_dmx512_rx.current_channel = 0;                   // 当前通道计数重置为0
    g_dmx512_rx.channel_count = 0;                     // 总通道数重置为0
    g_dmx512_rx.frame_ready = false;                   // 帧就绪标志重置为false
    
    /* 清空接收缓冲区：避免残留上一帧数据影响当前帧 */
    memset(g_dmx512_rx.rx_buffer, 0, DMX512_RX_BUFFER_SIZE);
}

/*!
    \brief      处理Break信号检测
    \param[in]  none
    \param[out] none
    \retval     none
    \note       DMX512帧起始标志：Break信号（低电平，持续时间≥92μs）
                检测到Break信号后，重置接收状态，准备接收后续的MAB（Mark After Break）和起始码
*/
static void dmx512_rx_process_break(void)
{
    uint32_t current_time = dmx512_rx_get_time_us(); // 获取当前时间戳（微秒）
    
    /* 1. 记录Break信号相关信息：开始时间、直接切换为数据接收状态、标记为正在接收 */
    g_dmx512_rx.break_start_time = current_time;    // 记录Break开始时间
    g_dmx512_rx.state = DMX512_RX_STATE_DATA;       // 直接切换为数据接收状态
    g_dmx512_rx.receiving = true;                   // 标记为正在接收
    
    /* 2. 重置接收状态：清空通道计数、错误标志，为新帧接收做准备 */
    g_dmx512_rx.current_channel = 0;
    g_dmx512_rx.channel_count = 0;
    g_dmx512_rx.error = DMX512_RX_ERROR_NONE;
    
    /* 3. 停止当前DMA传输：Break信号后需重新配置DMA，接收新帧数据 */
    dma_channel_disable(DMX512_RX_DMA_CHANNEL);
    
    /* 4. 直接启动DMA接收完整帧（513字节：起始码+512通道数据） */
    dma_memory_address_config(DMX512_RX_DMA_CHANNEL, (uint32_t)g_dmx512_rx.rx_buffer);
    dma_transfer_number_config(DMX512_RX_DMA_CHANNEL, 513);  /* 接收完整帧 */
    dma_channel_enable(DMX512_RX_DMA_CHANNEL);
    
    g_dmx512_rx.frame_start_time = current_time;
}

/*!
    \brief      处理接收到的数据
    \param[in]  data: 接收到的数据字节（UART_RDATA寄存器的值）
    \param[out] none
    \retval     none
    \note       根据当前接收器状态处理数据：
                - Break状态：接收到首字节（起始码），启动DMA接收剩余512字节
                - 数据状态：由DMA批量处理，此函数不操作
                - 其他状态：视为噪声，忽略处理
*/
static void dmx512_rx_process_data(uint8_t data)
{
    /* 此函数不再使用，因为已完全禁用RBNE中断，数据接收完全依赖DMA */
    (void)data; /* 避免编译器警告 */
}

/*!
    \brief      完成帧接收
    \param[in]  none
    \param[out] none
    \retval     none
    \note       帧接收完成流程：计算通道数→双缓冲复制→更新统计信息→标记帧就绪→触发回调→重置状态
                双缓冲设计（rx_buffer接收缓冲、data_buffer应用缓冲）避免数据覆盖
*/
static void dmx512_rx_complete_frame(void)
{
    /* 1. 计算接收到的总字节数和通道数：
       - remaining：DMA剩余传输数量
       - total_received：DMA实际接收字节数（513 - 剩余）
       - channel_count：通道数（总字节数-1，减去起始码） */
    uint16_t remaining = dma_transfer_number_get(DMX512_RX_DMA_CHANNEL);
    uint16_t total_received = 513 - remaining; /* DMA配置为接收513字节完整帧 */
    g_dmx512_rx.channel_count = total_received - 1; /* 减去起始码得到通道数（1-512） */
    
    /* 2. 双缓冲复制：将接收缓冲区（rx_buffer）数据复制到应用缓冲区（data_buffer）
       避免应用层读取时，DMA继续写入覆盖数据 */
    memcpy(g_dmx512_rx.data_buffer, g_dmx512_rx.rx_buffer, total_received);
    
    /* 3. 更新统计信息：
       - frames_received：总接收帧数+1
       - frames_valid：有效帧数+1（当前帧无错误）
       - last_frame_time：记录最后一帧接收完成时间戳 */
    g_dmx512_rx.stats.frames_received++;
    g_dmx512_rx.stats.frames_valid++;
    g_dmx512_rx.stats.last_frame_time = dmx512_rx_get_time_us();
    
    /* 4. 标记帧就绪：设置标志位，通知应用层有新帧数据 */
    g_dmx512_rx.frame_ready = true;
    g_dmx512_rx.state = DMX512_RX_STATE_COMPLETE; /* 状态切换为接收完成 */
    
    /* 5. 触发帧接收完成回调：如果应用层注册了回调函数，则调用 */
    if (g_dmx512_rx.frame_received_callback != NULL) {
        g_dmx512_rx.frame_received_callback(g_dmx512_rx.data_buffer, total_received);
    }
    
    /* 6. 重置状态：准备接收下一帧（状态切换为空闲，标记为未接收） */
    g_dmx512_rx.state = DMX512_RX_STATE_IDLE;
    g_dmx512_rx.receiving = false;
}

/*!
    \brief      处理接收错误
    \param[in]  error: 错误类型（枚举类型）
    \param[out] none
    \retval     none
    \note       错误处理流程：记录错误→更新统计信息→错误抑制→触发回调→重置状态
                错误抑制机制：相同错误1秒内仅报告一次，避免频繁触发回调（如持续噪声）
*/
static void dmx512_rx_handle_error(dmx512_rx_error_t error)
{
    // 静态变量：记录上一次错误时间、错误类型、错误计数（用于错误抑制）
    static uint32_t last_error_time = 0;
    static dmx512_rx_error_t last_error_type = DMX512_RX_ERROR_NONE;
    static uint32_t error_count = 0;
    
    /* 1. 记录错误信息：更新当前错误类型、状态、统计信息 */
    g_dmx512_rx.error = error;
    g_dmx512_rx.state = DMX512_RX_STATE_ERROR; /* 状态切换为错误 */
    g_dmx512_rx.stats.frames_error++;         /* 错误帧数+1 */
    g_dmx512_rx.stats.last_error = error;     /* 记录最后一次错误类型 */
    
    /* 2. 错误抑制机制：相同错误1秒内仅报告一次，避免频繁回调 */
    uint32_t current_time = dmx512_rx_get_time_us();
    if (error == last_error_type) {
        error_count++; // 相同错误，计数+1
        /* 如果时间间隔小于1秒（1000000微秒），不触发回调，直接重置状态 */
        if ((current_time - last_error_time) < 1000000) { /* 1秒 = 1000000微秒 */
            dmx512_rx_reset_state();
            return;
        }
    } else {
        error_count = 1; // 不同错误，计数重置为1
    }
    
    /* 3. 触发错误回调：如果应用层注册了回调函数，则调用 */
    if (g_dmx512_rx.error_callback != NULL) {
        g_dmx512_rx.error_callback(error);
    }
    
    /* 4. 更新错误记录：记录当前错误时间、错误类型 */
    last_error_time = current_time;
    last_error_type = error;
    
    /* 5. 重置状态：恢复到空闲状态，准备接收下一帧 */
    dmx512_rx_reset_state();
}

/*!
    \brief      获取当前时间(微秒)
    \param[in]  none
    \param[out] none
    \retval     当前时间(微秒)
    \note       简化实现：直接读取SysTick->VAL寄存器（24位计数器，递减计数）
                实际应用中需结合SysTick溢出中断，实现32位无溢出时间戳
*/
static uint32_t dmx512_rx_get_time_us(void)
{
    /* 使用系统滴答定时器获取时间：
       SysTick->VAL：当前计数值（递减），时钟频率为HCLK（如48MHz）
       简化实现：直接返回VAL值，实际需根据HCLK频率计算微秒数（如HCLK=48MHz，1个计数=1/48微秒） */
    return SysTick->VAL; /* 简化实现，实际应用中可能需要更精确的时间戳 */
}

/*!
    \brief      DMX512接收器UART中断处理函数
    \param[in]  none
    \param[out] none
    \retval     none
    \note       UART中断类型：接收缓冲区非空（RBNE）、空闲线路检测（IDLE）、错误（PERR等）
                中断处理优先级：错误中断 > IDLE中断 > RBNE中断，确保异常优先处理
*/
void dmx512_rx_uart_irq_handler(void)
{
    uint8_t data; // 存储接收的数据字节
    
    /* 1. 处理接收缓冲区非空中断（RBNE）：有新数据到达UART接收寄存器 */
    if (SET == usart_interrupt_flag_get(DMX512_RX_UART, USART_INT_FLAG_RBNE)) {
        data = usart_data_receive(DMX512_RX_UART); // 读取UART接收数据寄存器
        
        dmx512_rx_process_data(data); // 调用数据处理函数，根据当前状态处理数据
    }
    
    /* 2. 处理空闲线路检测中断（IDLE）：检测到DMX512的Break信号（低电平持续） */
    if (SET == usart_interrupt_flag_get(DMX512_RX_UART, USART_INT_FLAG_IDLE)) {
        usart_interrupt_flag_clear(DMX512_RX_UART, USART_INT_FLAG_IDLE); // 清除中断标志（必须读取DR后清除）
        
        /* 仅在IDLE状态下处理Break信号，其他状态（如数据接收）忽略IDLE中断，避免干扰 */
        if (g_dmx512_rx.state == DMX512_RX_STATE_IDLE) {
            dmx512_rx_process_break(); // 调用Break信号处理函数
        }
        /* DMA接收期间的IDLE中断被忽略，避免干扰数据接收 */
    }
    
    /* 3. 处理错误中断（PERR：奇偶校验错误） */
    if (SET == usart_interrupt_flag_get(DMX512_RX_UART, USART_INT_FLAG_PERR)) {
        usart_interrupt_flag_clear(DMX512_RX_UART, USART_INT_FLAG_PERR); // 清除中断标志
        dmx512_rx_handle_error(DMX512_RX_ERROR_PARITY); // 调用错误处理函数，类型为奇偶校验错误
    }
}

/*!
    \brief      DMX512接收器DMA中断处理函数
    \param[in]  none
    \param[out] none
    \retval     none
    \note       DMA中断类型：传输完成（FTF）、传输错误（ERR）
                传输完成：校验起始码→调试信息→禁用DMA→完成帧接收
                传输错误：清除标志→调试信息→错误处理
*/
void dmx512_rx_dma_irq_handler(void)
{
    /* 1. 处理DMA传输完成中断（FTF：Full Transfer Flag） */
    if (dma_interrupt_flag_get(DMX512_RX_DMA_CHANNEL, DMA_INT_FLAG_FTF)) {
        /* 清除DMA传输完成中断标志（必须清除，否则会重复触发） */
        dma_interrupt_flag_clear(DMX512_RX_DMA_CHANNEL, DMA_INT_FLAG_FTF);
        
        /* 获取DMA接收状态（剩余字节数、实际接收字节数） */
        uint16_t remaining = dma_transfer_number_get(DMX512_RX_DMA_CHANNEL);
        uint16_t total_received = 513 - remaining;  /* DMA配置为接收513字节完整帧 */
        
        /* 2. 验证起始码：DMX512标准起始码为0x00（NULL起始码），非0x00则判定为无效帧 */
        if (g_dmx512_rx.rx_buffer[0] != DMX512_START_CODE) {
            dmx512_rx_handle_error(DMX512_RX_ERROR_INVALID_START_CODE); // 调用错误处理函数
            return;
        }
        
        /* 调试信息：打印起始码验证通过日志 */
        printf("\r\n[DEBUG] 起始码验证通过: 0x%02X", g_dmx512_rx.rx_buffer[0]);
        
        /* 调试：打印完整DMX512数据（每16字节换行，便于阅读） */
        printf("\r\n[DEBUG] 完整DMX512数据 (%d字节): \r\n", total_received);
        for (int i = 0; i < total_received; i++) {
            printf("%02X ", g_dmx512_rx.rx_buffer[i]);
            /* 每16个字节换行，便于阅读 */
            if ((i + 1) % 16 == 0) {
                printf("\r\n");
            }
        }
        if (total_received % 16 != 0) { // 最后一行不足16字节，补换行
            printf("\r\n");
        }
        
        /* 3. 禁用DMA通道：传输完成后禁用，避免后续误触发 */
        dma_channel_disable(DMX512_RX_DMA_CHANNEL);
        
        /* 4. 完成帧接收：仅在数据接收状态下执行，确保流程正确 */
        if (g_dmx512_rx.state == DMX512_RX_STATE_DATA) {
            dmx512_rx_complete_frame(); // 调用帧接收完成函数
        }
        
    }
    
    /* 5. 处理DMA传输错误中断（ERR：Error Flag） */
    if (dma_interrupt_flag_get(DMX512_RX_DMA_CHANNEL, DMA_INT_FLAG_ERR)) {
        /* 清除DMA错误中断标志（必须清除，否则会重复触发） */
        dma_interrupt_flag_clear(DMX512_RX_DMA_CHANNEL, DMA_INT_FLAG_ERR);
        
        dmx512_rx_handle_error(DMX512_RX_ERROR_DMA); // 调用错误处理函数，类型为DMA错误
    }
}



/*!
    \brief      获取错误描述字符串
    \param[in]  error: 错误类型（枚举类型）
    \param[out] none
    \retval     错误描述字符串（如"无错误"、"帧错误"）
    \note       应用层可通过此函数将错误枚举值转换为可读字符串，用于日志打印或UI显示
*/
const char* dmx512_rx_get_error_string(dmx512_rx_error_t error)
{
    // 根据错误类型返回对应的描述字符串
    switch (error) {
        case DMX512_RX_ERROR_NONE:
            return "无错误";
        case DMX512_RX_ERROR_FRAMING:
            return "帧错误";
        case DMX512_RX_ERROR_OVERRUN:
            return "溢出错误";
        case DMX512_RX_ERROR_PARITY:
            return "奇偶校验错误";
        case DMX512_RX_ERROR_BREAK_TOO_SHORT:
            return "Break信号太短";
        case DMX512_RX_ERROR_MAB_TOO_SHORT:
            return "MAB信号太短";
        case DMX512_RX_ERROR_INVALID_START_CODE:
            return "无效起始码";
        case DMX512_RX_ERROR_TIMEOUT:
            return "接收超时";
        case DMX512_RX_ERROR_DMA:
            return "DMA错误";
        default:
            return "未知错误";
    }
}

/*!
    \brief      获取状态描述字符串
    \param[in]  state: 状态类型（枚举类型）
    \param[out] none
    \retval     状态描述字符串（如"空闲"、"数据接收"）
    \note       应用层可通过此函数将状态枚举值转换为可读字符串，用于日志打印或UI显示
*/
const char* dmx512_rx_get_state_string(dmx512_rx_state_t state)
{
    // 根据状态类型返回对应的描述字符串
    switch (state) {
        case DMX512_RX_STATE_IDLE:
            return "空闲";
        case DMX512_RX_STATE_BREAK:
            return "Break检测";
        case DMX512_RX_STATE_MAB:
            return "MAB等待";
        case DMX512_RX_STATE_START_CODE:
            return "起始码接收";
        case DMX512_RX_STATE_DATA:
            return "数据接收";
        case DMX512_RX_STATE_COMPLETE:
            return "接收完成";
        case DMX512_RX_STATE_ERROR:
            return "错误状态";
        default:
            return "未知状态";
    }
}

/*!
    \brief      处理调试信息（主循环调用）
    \param[in]  none
    \param[out] none
    \retval     none
    \note       主循环调用此函数处理ISR中产生的调试信息，避免在ISR中执行耗时的printf操作
*/
void dmx512_rx_process_debug_info(void)
{
    /* 检查是否有待处理的调试信息 */
    if (!g_dmx512_rx.debug_info.pending) {
        return;
    }
    
    /* 输出关键的调试信息，适度控制频率 */
    static uint32_t print_counter = 0;
    
    switch (g_dmx512_rx.debug_info.event) {
        case DMX512_DEBUG_EVENT_BREAK_DETECTED:
            /* 每5次Break信号输出一次 */
            if (print_counter % 5 == 0) {
                printf("\r\n[DEBUG] 检测到Break信号");
            }
            print_counter++;
            break;
            
        case DMX512_DEBUG_EVENT_FRAME_COMPLETE:
            /* 每5帧输出一次帧完成信息 */
            if (print_counter % 5 == 0) {
                printf("\r\n[DEBUG] 帧接收完成，通道数: %d", g_dmx512_rx.channel_count);
            }
            break;
            
        case DMX512_DEBUG_EVENT_DATA_START:
            /* 每5次数据开始输出一次 */
            if (print_counter % 5 == 0) {
                printf("\r\n[DEBUG] Break结束，启动DMA接收%d字节，首字节: 0x%02X", 512, g_dmx512_rx.debug_info.data_byte);
            }
            break;
            
        case DMX512_DEBUG_EVENT_DMA_COMPLETE:
            /* 每5次DMA完成输出一次 */
            if (print_counter % 5 == 0) {
                printf("\r\n[DEBUG] DMA传输完成中断");
                printf("\r\n[DEBUG] DMA接收字节数: %d, 总接收: %d (剩余: %d)", 
                       g_dmx512_rx.debug_info.dma_received, 
                       g_dmx512_rx.debug_info.total_received, 
                       g_dmx512_rx.debug_info.remaining);
            }
            break;
            
        case DMX512_DEBUG_EVENT_START_VALID:
            /* 每5次起始码验证输出一次 */
            if (print_counter % 5 == 0) {
                printf("\r\n[DEBUG] 起始码验证通过: 0x%02X", g_dmx512_rx.debug_info.data_byte);
            }
            break;
            
        case DMX512_DEBUG_EVENT_INVALID_START:
            printf("\r\n[DEBUG] 无效起始码: 0x%02X (期望0x%02X)", g_dmx512_rx.debug_info.data_byte, DMX512_START_CODE);
            break;
            
        case DMX512_DEBUG_EVENT_DMA_ERROR:
            printf("\r\n[DEBUG] DMA传输错误中断");
            break;
            
        /* 其他事件保持静默 */
        case DMX512_DEBUG_EVENT_BREAK_COMPLETE:
        default:
            break;
    }
    
    /* 清除待处理标志 */
    g_dmx512_rx.debug_info.pending = false;
    g_dmx512_rx.debug_info.event = DMX512_DEBUG_EVENT_NONE;
}

/*!
    \brief      打印完整DMX512数据（主循环调用）
    \param[in]  none
    \param[out] none
    \retval     none
    \note       主循环调用此函数打印完整的DMX512帧数据，避免在ISR中执行耗时操作
*/
void dmx512_rx_print_frame_data(void)
{
    /* 仅在帧就绪时打印数据 */
    if (!g_dmx512_rx.frame_ready) {
        return;
    }
    
    uint16_t total_received = g_dmx512_rx.channel_count + 1; /* 起始码 + 通道数据 */
    
    /* 打印完整DMX512数据（每16字节换行，便于阅读） */
    printf("\r\n[DEBUG] 完整DMX512数据 (%d字节): \r\n", total_received);
    for (int i = 0; i < total_received; i++) {
        printf("%02X ", g_dmx512_rx.data_buffer[i]);
        /* 每16个字节换行，便于阅读 */
        if ((i + 1) % 16 == 0) {
            printf("\r\n");
        }
    }
    if (total_received % 16 != 0) { /* 最后一行不足16字节，补换行 */
        printf("\r\n");
    }
}